﻿using System;
using System.Collections;
using System.Web;
using jade.wrapper;
using log4net;
using jade.core;
using System.Threading;
using System.Web.Services.Protocols;
using AgentState=jade.wrapper.AgentState;
using System.IO;
using System.Reflection;

namespace Web
{
    /// <summary>
    /// Initialization of whole jade2ws gateway is performed by this class.
    /// </summary>
    public class Global : System.Web.HttpApplication
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(Global));
         protected void Application_Start(object sender, EventArgs e)
        {             
        }


        protected void Session_Start(object sender, EventArgs e)
        {            
        }

        protected void Application_BeginRequest(object sender, EventArgs e)
        {
            HttpApplication app = (HttpApplication)sender;
            HttpContext context = app.Context;
            FirstRequestInitialization.Initialize(context);
            
            log.Debug("Start request");
            // if it's GET method, it must be WSDL request
            // otherwise it's SOAP request
            if (context.Request.HttpMethod == "GET")
            {

                if (context.Request.RawUrl.EndsWith("?wsdl") || context.Request.RawUrl.EndsWith("?WSDL"))
                {
                    String originalPath = context.Request.Path.ToLower();
                    context.RewritePath(originalPath.Replace(".agent", ".wsdl"));

                }
                
            }
             
        }

        protected void Application_EndRequest(object sender, EventArgs e)
        {
            log.Debug("End request");
        }

        protected void Application_AuthenticateRequest(object sender, EventArgs e)
        {

        }

        protected void Application_Error(object sender, EventArgs e)
        {
            log.Error("Application error",Server.GetLastError());
            //TODO: enhance soap fault processing
            if (Server.GetLastError() is SoapException)
            {
                Response.Write("soap exception, not complete yet :-) ");
                Response.Write(Server.GetLastError());

                Server.ClearError();
            }
            
            log.Error(Server.GetLastError().StackTrace);
        }

        protected void Session_End(object sender, EventArgs e)
        {
            log.Debug("session end");
        }

        protected void Application_End(object sender, EventArgs e)
        {
            jade.wrapper.AgentContainer container = (jade.wrapper.AgentContainer)Context.Application.Get("container");
            if (container == null)
            {
                log.Info("Ending Agent platform");
                container.kill();
                Context.Application.Set("container", null);                              
                log.Info("Agent platform is down!");
            }
        }
    }

    /// <summary>
    /// due to problems with integrated pipeline on IIS 7.5 is first initialization done by this class. Otherwise should be enough to initilize application in application_start() method.
    /// </summary>
    class FirstRequestInitialization
    {

        private static bool s_InitializedAlready = false;
        private static Object s_lock = new Object();
        private static readonly ILog log = LogManager.GetLogger(typeof(Global));
        

        // Initialize only on the first request

        public static void Initialize(HttpContext context)
        {

            if (s_InitializedAlready)
            {

                return;
            }

            lock (s_lock)
            {

                if (s_InitializedAlready)
                {

                    return;
                }

                performCleaning(context);
                performInit(context);

                s_InitializedAlready = true;
            }

        }
        /// <summary>
        /// delete all wsdls and wsil file before first start
        /// </summary>
        /// <param name="context"></param>
        private static void performCleaning(HttpContext context)
        {
            DirectoryInfo di = new DirectoryInfo( context.Server.MapPath("~/wsdl/"));
            FileInfo[] rgFiles = di.GetFiles("*.ws*");
            foreach (FileInfo fi in rgFiles)
            {
                fi.Delete();
            }
        }

        /// <summary>
        /// run agent container including all unil.agents
        /// </summary>
        /// <param name="context"></param>
        private static void performInit(HttpContext context)
        {
            jade.wrapper.AgentContainer container = (jade.wrapper.AgentContainer)context.Application.Get("container");
            if (container == null)
            {
                // start agent container
                log.Debug("starting platform");
                Profile profile = new ProfileImpl(context.Server.MapPath("~/config/leap.properties"));
                profile.setParameter("jade_domain_df_autocleanup", "true");

                Runtime rt = Runtime.instance();
                container = rt.createAgentContainer(profile);
                log.Debug("container started");


                // allow continue only if gateway agent exist in container
                AgentController gw = null;
                AgentController subscrAgent = null;

                Hashtable wsStore = new Hashtable();

                try
                {
                    HttpRequest req = context.Request;
                    string appPath = context.Request.ApplicationPath;
                    string urlLocale = context.Request.Url.GetLeftPart(UriPartial.Authority) + appPath +"/";
                    log.Debug("url locale " + urlLocale);
                    //urlLocale += context.Request.ApplicationPath;
                    string path = context.Server.MapPath("~/wsdl/");
                    log.Error("wsdl path " + path);
                    string logPath = context.Server.MapPath("~/logs/");
                    if (log.IsDebugEnabled)
                    {
                        log.Debug("AppDomain.CurrentDomain.RelativeSearchPath = " + AppDomain.CurrentDomain.RelativeSearchPath);
                        log.Debug("AppDomain.CurrentDomain.BaseDirectory=" + AppDomain.CurrentDomain.BaseDirectory);
                        log.Debug("AppDomain.CurrentDomain.DynamicDirectory=" + AppDomain.CurrentDomain.DynamicDirectory);
                        
                        Assembly[] ass = AppDomain.CurrentDomain.GetAssemblies();
                        foreach (Assembly a in ass)
                        {
                            log.Debug("Available assembly: " +a.GetName() + ", " + a.Location);
                        }
                    }
                    subscrAgent = container.createNewAgent("subscriptionAgent", "GatewayUtil.agents.SubscriptionAgent", new object[] { wsStore, urlLocale, path });
                    subscrAgent.start();
                    subscrAgent.activate();
                    //Thread.Sleep(3000);

                    State state = subscrAgent.getState();
                    while (!(state.getCode() == AgentState.AGENT_STATE_IDLE.getCode()))
                    {
                        Thread.Sleep(100);
                        state = subscrAgent.getState();
                    }

                    gw = container.createNewAgent("gwAgent", "GatewayUtil.agents.GatewayAgent", null);
                    gw.start();

                    container.createNewAgent("wsInvokerAgent", "GatewayUtil.agents.WSInvokerAgent", null).start();
                    container.createNewAgent("weatherAgent", "Agents.WeatherAgent", new object[] { logPath}).start();
                }
                catch (ControllerException exception)
                {
                    log.Error(exception);
                    throw exception;
                }


                context.Application.Add("container", container);
                context.Application.Add("gwAgent", gw);
                context.Application.Add("wsStore", wsStore);
                log.Info("Agent container with gateway agent started");
            }

        }

    }



}